﻿
using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using Test30.Util;

namespace Test30.Engine
{
    public class Equipment : IItemCollection
    {
        public readonly GameEvent<Item, EventArgs> ItemEquipped = new GameEvent<Item, EventArgs>();
        public readonly GameEvent<Item, EventArgs> ItemChanged = new GameEvent<Item, EventArgs>();

        public int Count => _items.Length;
        public int Max => Count;
        public Item MeleeWeapon => this["Melee Weapon"];

        public Item this[int index]
        {
            get
            {
                if (index >= Count) return null;
                return _items[index] ; }
        }
        public Item this[string category]
        {
            get
            {
                for (int i = 0; i < _categories.Length; i++)
                {
                    if (_categories[i] == category)
                    {
                        return _items[i];
                    }
                }

                // category was not found
                return null;
            }
        }
        public Equipment()
        {
            //### bob: temp. should be data driven
            // fill in the allowed category for each slot
            _categories = new[]
                {
                    "Melee Weapon",
                    "Missile Weapon",
                    "Ammunition",
                    "Ring",
                    "Ring",
                    "Necklace",
                    "Light Source",
                    "Torso",
                    "Cloak",
                    "Shield",
                    "Helm",
                    "Gloves",
                    "Boots"
                };

            _items = new Item[_categories.Length];
        }

        public IEnumerator<Item> GetEnumerator()
        {
            return ((IEnumerable<Item>)_items).GetEnumerator();
        }
        public void Remove(NotNull<Item> item)
        {
            if (!_items.Contains(item.Value)) throw new InvalidOperationException("Cannot unequip an item that is not currently equipped.");

            // find the slot
            int index = _items.IndexOfFirst((thisItem) => item.Value == thisItem);

            _items[index].Changed -= Item_Changed;

            // empty it
            _items[index] = null;

            ItemEquipped.Raise(item, EventArgs.Empty);
        }

        IEnumerator IEnumerable.GetEnumerator()
        {
            return _items.GetEnumerator();
        }

        

        public string GetCategory(int index)
        {
            if (index < Count)
            {
                return _categories[index];
            }

            return String.Empty;
        }
        public IEnumerable<Item> GetEquipped(bool includeMeleeWeapon, bool includeMissileWeapons)
        {
            foreach (Item item in this)
            {
                if (item != null)
                {
                    // skip over the other weapon type
                    if (!includeMeleeWeapon && (item.Type.Category == "Melee Weapon")) continue;
                    if (!includeMissileWeapons && (item.Type.Category == "Missile Weapon")) continue;
                    if (!includeMissileWeapons && (item.Type.Category == "Ammunition")) continue;

                    yield return item;
                }
            }
        }

        private void Item_Changed(object sender, EventArgs e)
        {
            ItemChanged.Raise((Item)sender, EventArgs.Empty);
        }

        private readonly string[] _categories;
        private readonly Item[] _items;
    }
}
